package com.gitee.wsl.doc.prosemirror.history

import com.gitee.wsl.doc.prosemirror.history.ext.histTransaction
import com.gitee.wsl.doc.prosemirror.state.Command
import com.gitee.wsl.doc.prosemirror.state.EditorState
import com.gitee.wsl.doc.prosemirror.state.actionCommand
import com.gitee.wsl.doc.prosemirror.util.safeMode


@Suppress("TooGenericExceptionCaught", "NestedBlockDepth")
fun buildCommand(redo: Boolean, scroll: Boolean): Command {
    return Command { state, dispatch ->
        try {
            val hist = historyKey.getState(state)
            if (hist == null || (if (redo) hist.undone else hist.done).eventCount == 0) {
                false
            } else {
                if (dispatch != null) {
                    hist.histTransaction(state, redo)?.let {
                        dispatch(
                            if (scroll) {
                                it.scrollIntoView()
                            } else {
                                it
                            }
                        )
                    }
                }
                true
            }
        } catch (ex: Exception) {
            if (!safeMode) throw ex
            false
        }
    }
}

/** A command function that undoes the last change, if any. */
val Command.Companion.undo: Command
    get() = buildCommand(redo = false, scroll = true)

/** A command function that redoes the last undone change, if any. */
val Command.Companion.redo: Command
    get() = buildCommand(redo = true, scroll = true)

/** A command function that undoes the last change. Don't scroll the selection into view. */
val Command.Companion.undoNoScroll: Command
    get() = buildCommand(redo = false, scroll = false)

/** A command function that redoes the last undone change. Don't scroll the selection into view. */
val Command.Companion.redoNoScroll: Command
    get() = buildCommand(redo = true, scroll = false)


fun EditorState.undo() = actionCommand(Command.undo)

fun EditorState.redo() = actionCommand(Command.redo)

fun EditorState.undoNoScroll() = actionCommand(Command.undoNoScroll)

fun EditorState.redoNoScroll() = actionCommand(Command.redoNoScroll)

